package com.xls.pet.service.impl;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.xls.pet.common.ResultCode;
import com.xls.pet.entity.Category;
import com.xls.pet.entity.Item;
import com.xls.pet.entity.ItemStock;
import com.xls.pet.exception.BusinessException;
import com.xls.pet.mapper.CategoryMapper;
import com.xls.pet.mapper.ItemMapper;
import com.xls.pet.mapper.ItemStockMapper;
import com.xls.pet.query.ItemQuery;
import com.xls.pet.service.ItemService;
import com.xls.pet.service.MinioService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

import static com.xls.pet.entity.table.ItemStockTableDef.ITEM_STOCK;
import static com.xls.pet.entity.table.ItemTableDef.ITEM;

/**
 * 服务层实现。
 *
 * @author xls
 * @since 2024-06-17
 */
@Service
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements ItemService {

    @Autowired
    MinioService minioService;

    @Autowired
    ItemMapper itemMapper;

    @Autowired
    ItemStockMapper itemStockMapper;

    @Autowired
    CategoryMapper categoryMapper;

    @Override
    public Page<Item> list(Integer pageNumber, Integer pageSize, Integer totalRow, ItemQuery itemQuery) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (itemQuery.getCategoryId() != null) {
            List<Integer> idList = categoryMapper.getchildCategoryIdList(itemQuery.getCategoryId());
            condition.and(ITEM.CATEGORY_ID.in(idList));
        }
        if (StringUtils.isNotBlank(itemQuery.getName())) {
            condition.and(ITEM.NAME.like(itemQuery.getName()));
        }
        Page<Item> page = this.page(Page.of(pageNumber, pageSize), condition);
        List<Item> itemList = page.getRecords();
        if (!itemList.isEmpty()) {
            List<Category> categoryList = categoryMapper.selectAll();
            itemList.forEach(item -> {
                categoryMapper.setCategoryName(categoryList, item);
            });
        }
        return page;
    }

    @Transactional
    @Override
    public void removeItem(Integer[] ids) {
        for (Integer id : ids) {
            ItemStock itemStock = itemStockMapper.selectOneByCondition(QueryCondition.create(ITEM_STOCK.ITEM_ID, id));
            if (itemStock != null) {
                throw new BusinessException(ResultCode.NOT_ALLOW_DELETE_ITEM);
            }
            String imageUrl = this.getById(id).getImage();
            if (StringUtils.isNotBlank(imageUrl)) {
                minioService.deleteFile(imageUrl);
            }
            this.removeById(id);
        }
    }

    @Override
    @Transactional
    public void saveItem(Item item) {
        Item oldItem = QueryChain.of(itemMapper)
                .select(ITEM.ID)
                .from(ITEM)
                .where(ITEM.NAME.eq(item.getName()))
                .one();
        if (oldItem == null) {
            this.save(item);
        } else {
            item.setId(oldItem.getId());
        }
        if (item.getQuantity() != null && item.getProductDate() != null) {
            ItemStock itemStock = ItemStock.builder()
                    .itemId(item.getId())
                    .quantity(item.getQuantity())
                    .weight(item.getWeight())
                    .productDate(item.getProductDate())
                    .price(item.getPrice())
                    .purchasePrice(item.getPurchasePrice())
                    .build();
            itemStock.calculateExpirationDate(item.getUnit(), item.getShelfLife());
            itemStockMapper.insert(itemStock);
        }
    }

    @Override
    public void updateItem(Item item) {
        Item oldItem = this.getById(item.getId());
        if (!Objects.equals(oldItem.getShelfLife(), item.getShelfLife()) || !Objects.equals(oldItem.getUnit(), item.getUnit())) {
            String expression = "DATE_ADD(product_date, INTERVAL " + item.getShelfLife();
            if (item.getUnit() == 1) {
                expression += " YEAR)";
            } else if (item.getUnit() == 2) {
                expression += " MONTH)";
            } else {
                expression += " DAY)";
            }
            UpdateChain.of(ItemStock.class)
                    .setRaw(ItemStock::getExpirationDate, expression)
                    .where(ItemStock::getItemId).eq(item.getId())
                    .update();
        }
        this.updateById(item);
    }
}
